#ifndef MESSAGE_QUEUE2_H_
#define MESSAGE_QUEUE2_H_

#include <sstream>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/msg.h>
#include <sys/ipc.h>
#include <stdio.h>
#include "logger.h"
#include "Exception.h"

typedef int MessageId_t;

template<class T>
struct MQMessage
{
	long mtype;             // Esto nunca hay q olvidarse de ponerlo!
	T data;

};

template<class T> class MessageQueue2
{
private:
    key_t clave;
    int id;
    std::string m_queueName;
    char m_key;
public:
    static const char DEFAULT_LETTER='a';

    /**
     *
     */
    MessageQueue2( std::string file, char c =DEFAULT_LETTER);

    /**
     *
     */
    ~MessageQueue2();

    /**
     *
     */
    void put(MessageId_t tipo, T dato );

    //TODO esta interfaz puede cambiar levemente para contemplar la salida
    //por destruccion de la mq
    T get(MessageId_t tipo);

    /**
     *
     */
    void destroy();
};

template<class T> MessageQueue2<T>::MessageQueue2( std::string archivo, char letra )
{
	m_queueName=archivo;
	m_key = letra;

	std::string touchCmd = "touch "+archivo;
	system(touchCmd.c_str());

	this->clave = ftok( archivo.c_str(), letra );
	if ( this->clave == -1 )
		throw Exception("Error in the message queue key: "+archivo );

   this->id = msgget( this->clave, 0777 | IPC_CREAT );
   if ( this->id == -1 )
	   throw Exception("Error while creating the message queue");
}

template<class T> MessageQueue2<T>::~MessageQueue2()
{
}

template<class T> void MessageQueue2<T>::destroy()
{
	if(msgctl( this->id, IPC_RMID, NULL ))
		throw Exception("Error while destroying the message queue");
}

template<class T> void MessageQueue2<T>::put(MessageId_t tipo, T dato )
{
	MQMessage<T> message;
	message.mtype = tipo;
    message.data = dato;

    std::stringstream ss;
    ss << "Mq " <<m_queueName<< " c:"<<m_key<<" put() tipo"<<tipo;

    CLogger::log(ss.str(),LogLevelEnum::DEBUG);

    if(msgsnd( this->id, ( const void * ) &message,sizeof(MQMessage<T>) - sizeof(long), 0 )<0)
    	throw Exception("Error while writing to message queue");

}

template<class T> T MessageQueue2<T>::get(MessageId_t tipo)
{
	MQMessage<T> message;

    std::stringstream ss;
    ss << "Mq " <<m_queueName<< " c:"<<m_key<<" get() tipo"<<tipo;

    CLogger::log(ss.str(),LogLevelEnum::DEBUG);

	if(msgrcv( this->id, ( void * ) &message, sizeof(MQMessage<T>) - sizeof(long),tipo, 0 )<0)
		throw Exception("Error while creating the message queue");

	return message.data;
}

#endif /* MESSAGE_QUEUE_H_ */
